<?php
/**
 * DB基类
 * User: liuqingwei
 * Date: 2020/3/28
 * Time: 下午9:51
 */

namespace  wei\core;

class DB
{
    private  $db_link;
    protected $query_num = 0;
    private static $instance;
    protected $PDO_statement;
    
    //事务数
    protected $trans_times = 0;
    protected $bind = [];
    public $rows = 0;
    
    /*
     * 初始化
     *
     * @param array $config 配置
     *
     * @return mixed
     */
    private function __construct($config)
    {
        $this->connect($config);
    }
    
    /**
     * 获取db实例
     *
     * @param array $config 配置
     *
     * @return object
     */
    public static function getInstance($config)
    {
        if (!(self::$instance instanceof self))
        {
            self::$instance = new self($config);
        }
        
        return self::$instance;
    }
    
    /**
     * 链接PDO
     *
     * @param array $config 配置信息
     *
     * @return object
     */
    public function connect(array $config)
    {
        try {
            $this->db_link = new \PDO($config['dsn'],$config['username'],$config['passward']);
        } catch(\PDOException $e) {
            throw new BaseException("数据库链接失败",1000,$e);
        }
        
        return $this->db_link;
    }
    
    /**
     * 查询
     * @param   string      $sql        查询sql
     * @param   array       $bind       绑定的sql相关参数
     * @param   int         $fetchType  结果集类型 结果集列名的数组
     * @throws  string      错误信息
     *
     * @return mixed
     */
    public function query(string $sql,array $bind,$fetchType = \PDO::FETCH_ASSOC)
    {
        if (!$this->db_link)
        {
            throw new \Exception("数据库链接失败");
        }
        
        $this->PDO_statement = $this->db_link->prepare($sql);
        $this->PDO_statement->execute($bind);
        $ret = $this->PDO_statement->fetchAll($fetchType);
        $this->rows = count($ret);
        return $ret;
    }
    
    /**
     * 执行器
     *
     * @param string $sql   查询sql
     * @param array  $bind  绑定的sql相关参数
     * @throws  string      错误信息
     *
     * @return mixed
     */
    public function execute(string $sql,array $bind)
    {
        if (!$this->db_link)
        {
            throw new \Exception("数据库链接失败");
        }
    
        $this->PDO_statement = $this->db_link->prepare($sql);
        $ret = $this->PDO_statement->execute($bind);
   
        
        $this->rows = $this->PDO_statement->rowCount();
        return $ret;
    }
    
    /**
     * 开启事务
     */
    public function startTrans()
    {
        ++$this->trans_times;
        
        //判断是否存在已有的事务,如果不存在已创建事务才开启新的事务
        if (1 == $this->trans_times)
        {
            $this->db_link->beginTransaction();
        }
        else
        {
            //设置事务保存点
            $this->db_link->execute("SAVEPOINT tr{$this->trans_times}");
        }
    }
    
    /**
     * 提交
     */
    public function commit()
    {
        if (1 == $this->trans_times)
        {
            $this->db_link->commit();
        }
        
        --$this->trans_times;
    }
    
    /**
     * 回滚
     */
    public function rollback()
    {
        if (1 == $this->trans_times)
        {
            $this->db_link->rollbacl();
        }
        elseif($this->trans_times > 1)
        {
            $this->db_link->execute("ROLLBACK TO SAVEPOINT tr{$this->trans_times}");
        }
        
        $this->trans_times = max(0,$this->trans_times-1);
    }
}